// 单例
const Singleton = (name) => {
    this.name = name;
}

Singleton.instance = null;
Singleton.prototype.getName = () => {
    console.log(name);
}

// 获取唯一对象，增加了不透明性
Singleton.getInstance = (name) => {
    if (!this.instance) {
        this.instance = new Singleton(name);
    }
    return this.instance
}

const a = Singleton.getInstance('a');
const b = Singleton.getInstance('b');

// a === b -> true

// 透明的单例
// const CreateDiv = (function() {
//     let instance;

//     const cd = function(html) {
//         if (instance) {
//             return instance;
//         }
//         this.html = html;
//         this.init();
//         return instance = this;
//     }

//     cd.prototype.init = () => {
//         const div = document.createElement('div');
//         div.innerHTML = this.html;
//         document.body.appendChild(div);
//     }

//     return cd;
// })
// const a = new CreateDiv('a');
// const b = new CreateDiv('b');
// a === b -> true

// 用代理来实现单例

const CreateDiv = function(html) {
    this.html = html;
    this.init();
}

CreateDiv.prototype.init = () => {
    const div = document.createElement('div');
    div.innerHTML = this.html;
    document.body.appendChild(div);
}

const proxySingletonCreateDiv = (function() {
    let instance;
    return function(html) {
        if (!instance) {
            instance = new CreateDiv(html);
        }
        return instance;
    }
})();

const a = new proxySingletonCreateDiv('a');
const b = new proxySingletonCreateDiv('b');

//a === b -> true

// var a = {};
// 使用命名空间降低全局污染
const namespace1 = {
    a: function() {},
    b: function() {}
}

const MyApp = {};
MyApp.namespace = function(name) {
    const parts = name.split('.');
    let current = MyApp;
    for (let i in parts) {
        if (!current[parts[i]]) {
            current[parts[i]] = {}
        }
        current = current[parts[i]]
    }
}
MyApp.namespace('event');
MyApp.namespace('dom.style');

const MyApp = {
    event: {},
    dom: {
        style: {}
    }
}
// 闭包封装私有变量
const user = function() {
    var __name__ = 'a';
    var __age__ = 29;
    return {
        getUserInfo: function() {
            return __name__ + '' + __age__
        }
    }
}
//惰性单例 -> singleton.html







// 策略 - 多种方式之间的互相替换
// 计算年终奖
// var calcBonus = function(performanceLevel, salary) {
//     if (performanceLevel === 'S') {
//         return salary * 4
//     }

//     if (performanceLevel === 'A') {
//         return salary * 3
//     }

//     if (performanceLevel === 'B') {
//         return salary * 2
//     }
// }

// java中的策略模式
// 策略
// var performanceS = function() {}
// performanceS.prototype.calc = function() {
//     return salary * 4;
// }
// var performanceA = function() {}
// performanceA.prototype.calc = function() {
//     return salary * 3;
// }
// var performanceB = function() {}
// performanceB.prototype.calc = function() {
//     return salary * 2;
// }
// // 奖金类
// var Bonus = function() {
//     this.salary = null; // 原始工资
//     this.strategy = null; // 绩效等级对应的策略对象
// }
// Bonus.prototype.setSalary = function(salary) {
//     this.salary = salary;
// }
// Bonus.prototype.setStrategy = function(strategy) {
//     this.strategy = strategy;
// }
// Bonus.prototype.getBonus = function() {
//     if (!this.strategy) {
//         throw new Error('no strategy');
//     }
//     return this.strategy.calc(this.salary);
// }
// var bonus = new Bonus();
// bonus.setSalary(10000)
// bonus.setStrategy(new performanceS());
// console.log(bonus.getBonus());

// javascript中的策略模式
var strategies = {
    'S': (salary) => {
        return salary * 4;
    },
    'A': (salary) => {
        return salary * 3;
    },
    'B': (salary) => {
        return salary * 2;
    }
}
var calcBonus = function(lv, salary) {
    return strategies[lv](salary)
}





// 代理模式 - 替身

// 男孩儿A 小明 -> 男孩儿B -> 女孩儿A
var Flower = function() {};
var xiaoming = {
    sendFlower: function(target) {
        var flower = new Flower();
        target.receiveFlower(flower);
    }
}

var B = {
    reviceFlower: function(flower) {
        A.listenGoodMood(function() { // 保护代理
            A.receiveFlower(flower);
        })
    }
}

var A = {
    receiveFlower: function() {
        console.log('收到');
    },
    listenGoodMood: function(fn) {
        setTimeout(function() {
            fn();
        }, 10000)
    }
}

xiaoming.sendFlower(B);

// 虚拟代理实现图片预加载
var myImage = (function() {
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);

    return {
        setSrc: function(src) {
            imgNode.src = src
        }
    }
})()

var proxyImage = function() {
    var img = new Image;
    img.onload = function() {
        myImage.setSrc(this.src);
    }
    return {
        setSrc: function(src) {
            myImage.setSrc('http://loading.gif');
            img.src = src;
        }
    }
}

proxyImage.setSrc('http://xxx.png');

myImage.setSrc('http://xxx.png');

// 不使用代理的图片预加载
var MyImage = (function() {
    var imgNode = document.createElement('img');
    document.body.appendChild(img);
    var img = new Image;
    img.onload = function() {
        imgNode.src = img.src;
    };
    return {
        setSrc: function(src) {
            imgNode.src = 'loading.gif';
            img.src = src;
        }
    }
})()

MyImage.setSrc('http://xxx.png');

// 单一职责

// 当代理对象和本体对象都是函数
var myImage = (function() {
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);

    return function(src) {
        imgNode.src = src
    }
})()

var proxyImage = (function() {
    var img = new Image;
    img.onload = function() {
        myImage(this.src);
    }
    return function(src) {
        myImage('http://loading.gif');
        img.src = src;
    }
})();

// 缓存代理
var mult = function() {
    console.log('start mult');
    var a = 1;
    for (var i = 0, l = arguments.length; i < l; i++) {
        a = a * arguments[i]
    }
    return a;
}

var proxyMult = (function() {
    var cache = [];
    return function() {
        var args = Array.prototype.join.call(arguments, ',');
        if (args in cache) {
            return cache[args]
        }
        return cache[args] = mult.apply(this, arguments);
    }
})()
proxyMult([1,2,3,4])
proxyMult([1,2,3,4])

// 变体
// - 防火墙
// - 远程代理
// - 保护代理
// - 智能引用代理
// - 写时复制代理 (from 虚拟代理) 典型场景dll动态链接库